Imports System.Text
Imports Microsoft.VisualStudio.RegularExpression.Parser
Imports Microsoft.VisualStudio.Text
Imports Microsoft.VisualStudio.Text.Classification
Imports System.ComponentModel.Composition


Namespace Microsoft.VisualStudio.RegularExpression.Coloring
    ''' <summary>
    ''' Implements the coloring classification.
    ''' </summary>
    Friend NotInheritable Class RegexClassifier
        Implements IClassifier
        Private buffer As ITextBuffer

        Private classificationTypeRegistry As IClassificationTypeRegistryService

        Friend Sub New(ByVal bufferToClassify As ITextBuffer, ByVal classificationTypeRegistry As IClassificationTypeRegistryService)
            Me.buffer = bufferToClassify
            Me.classificationTypeRegistry = classificationTypeRegistry
        End Sub

        'Coloring some expressions may affect other lines. The classifier is called for a specific line, so we
        'need to instruct it to be called again for each line that may be affected. This code calls the colorizer
        'for any span that will be affected.
        Private Sub RecolorizeAffectedLines(ByVal span As Span, ByVal snapshot As ITextSnapshot)
            If span.End > span.Start Then
                OnClassificationChanged(New SnapshotSpan(snapshot, span.Start, span.End - span.Start))
            End If
        End Sub

#Region "IClassifier Members"

        ' Use this event if a text change causes classifications on a line other the one on which the line occurred.
        Public Event ClassificationChanged As EventHandler(Of ClassificationChangedEventArgs) Implements IClassifier.ClassificationChanged

        Friend Sub OnClassificationChanged(ByVal span As SnapshotSpan)
            RaiseEvent ClassificationChanged(Me, New ClassificationChangedEventArgs(span))
        End Sub

        'This is the main method of the classifier. It should return one ClassificationSpan per group that needs coloring.
        'It will be called with a span that spans a single line where the edit has been made (or multiple times in paste operations).
        Public Function GetClassificationSpans(ByVal span As SnapshotSpan) As IList(Of ClassificationSpan) Implements IClassifier.GetClassificationSpans
            Dim classificationSpans As New List(Of ClassificationSpan)

            'Create a parser to parse the regular expression, and return the classification spans defined by it.
            For Each token As Token In span.Snapshot.TextBuffer.Properties.GetProperty(Of ParserRunner)(GetType(ParserRunner)).Parser.Tokens
                If token.Kind = TokenKind.Capture Then
                    classificationSpans.Add(New ClassificationSpan(New SnapshotSpan(span.Snapshot, token.Start, 1), classificationTypeRegistry.GetClassificationType(ClassificationTypes.Capture)))
                    classificationSpans.Add(New ClassificationSpan(New SnapshotSpan(span.Snapshot, token.End - 1, 1), classificationTypeRegistry.GetClassificationType(ClassificationTypes.Capture)))
                Else
                    classificationSpans.Add(New ClassificationSpan(New SnapshotSpan(span.Snapshot, token.Start, token.End - token.Start), classificationTypeRegistry.GetClassificationType(token.TranslateEnumToString(token.Kind))))
                End If

                If span.IntersectsWith(New Span(token.Start, token.End)) AndAlso Not (span.Start.Position <= token.Start AndAlso span.End.Position >= token.End) AndAlso (token.Kind = TokenKind.Capture OrElse token.Kind = TokenKind.CharGroup OrElse token.Kind = TokenKind.Multiplier) Then
                    RecolorizeAffectedLines(New Span(span.End, token.End - span.End.Position), span.Snapshot)
                End If
            Next token

            Return classificationSpans
        End Function

#End Region
    End Class
End Namespace